/* ===================

AX2E (AXESCON XACML 2.0 Engine) is the Java authorization engine, which implements OASIS XACML 2.0 standard.
Copyright (C) 2007 AXESCON LLC

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA


Contact: AXESCON LLC - info{at}axescon.com

 =================== */
package axescon.xacml.engine.fn;

import axescon.xacml.api.*;
import axescon.xacml.model.ctx.XacmlCtx;
import axescon.xacml.model.policy.Expression;
import axescon.xacml.model.shared.attr.StringAttribute;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import x0ContextSchemaOs.oasisNamesTcXacml2.RequestType;

import java.util.Arrays;
import java.util.List;

/**
 * @author Date: Sep 28, 2005
 *         Responsibilities: see A.3.15 XPath-based functions
 */
public class FnXpathNodeMatch extends AbstractFn {
    public int getArgTypeListLength() {
        return 2;
    }
    public Liquid exec(Liquid[] args) throws ExpressionEvalIndeterminateException {
        throw new ExpressionEvalIndeterminateException("FnXpathNodeMatch.exec(AttributeValue[][] args) method shouldn't be ever called.");
    }

    public Liquid exec(Expression[] args, CtxHandler ch, XacmlCtx req, ExpressionEvaluator ee) throws ExpressionEvalIndeterminateException {
        if (args == null || args.length != 2 || args[0] == null || args[1] == null)
            throw new ExpressionEvalIndeterminateException("FnXpathNodeMatch# argument is empty or too long.");
        if (!(args[0] instanceof StringAttribute))
            throw new ExpressionEvalIndeterminateException("FnXpathNodeMatch# arg0 is not xpath string.");
        if (!(args[1] instanceof StringAttribute))
            throw new ExpressionEvalIndeterminateException("FnXpathNodeMatch# arg1 is not xpath string.");

        StringAttribute xpathAttr0 = (StringAttribute) args[0];
        StringAttribute xpathAttr1 = (StringAttribute) args[1];


        String xpath0 = xpathAttr0.getStringValue();
        String xpath1 = xpathAttr1.getStringValue();

        xpath0 = args[0].getRootPolicyObject().getNamespacesDecls() + xpath0;
        xpath1 = args[1].getRootPolicyObject().getNamespacesDecls() + xpath1;


        try {
            RequestType rt = (RequestType) req.getLLObject();
            XmlObject[] xobjs0 = rt.selectPath(xpath0);
            XmlObject[] xobjs1 = rt.selectPath(xpath1);

            //idea is to traverse from second array elements to root of the doc
            // if first array element is encountered then match is successfull

            //List<XmlObject>
            List x0 = Arrays.asList(xobjs0);
            for (int i = 0; i < xobjs1.length; i++) {

                XmlCursor cur = xobjs1[i].newCursor();

                do {
                    if (x0.contains(cur.getObject())) return returnBoolean(true);
                } while (cur.toParent());

                cur.dispose();
            }
            return returnBoolean(false);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExpressionEvalIndeterminateException("FnXpathNodeMatch# can't evaluate xpaths:" + xpath0 +
                    ", " + xpath1, e);
        }
    }
    public Class getReturnDataType() throws ExpressionEvalIndeterminateException {
        return super.getBooleanReturnDataType();
    }
   
}
